#include "StdAfx.h"


#ifndef EXCLUDE_SCALEFORM_SDK


#include "SharedResources.h"
#include "SharedStates.h"
#include "GFxVideoWrapper.h"
#include "GImageInfoXRender.h"
#include "FlashPlayerInstance.h"
#include <CrySizer.h>
#include <ISystem.h>

#include "gconfig.h"


#ifdef GHEAP_TRACE_ALL

//////////////////////////////////////////////////////////////////////////
// CryMemReplayGHeapTracer

class CryMemReplayGHeapTracer : public GMemoryHeap::HeapTracer
{
public:
	void OnCreateHeap(const GMemoryHeap* heap)
	{
	}

	void OnDestroyHeap(const GMemoryHeap* heap)
	{
	}

	void OnAlloc(const GMemoryHeap* heap, UPInt size, UPInt align, unsigned sid, const void* ptr)
	{
		MEMREPLAY_SCOPE(EMemReplayAllocClass::C_UserPointer, EMemReplayUserPointerClass::C_CryMalloc);
		MEMREPLAY_SCOPE_ALLOC(ptr, size, align);
	}

	void OnRealloc(const GMemoryHeap* heap, const void* oldPtr, UPInt newSize, const void* newPtr)
	{
		MEMREPLAY_SCOPE(EMemReplayAllocClass::C_UserPointer, EMemReplayUserPointerClass::C_CryMalloc);
		MEMREPLAY_SCOPE_REALLOC(oldPtr, newPtr, newSize, 0);
	}

	void OnFree(const GMemoryHeap* heap, const void* ptr)
	{
		MEMREPLAY_SCOPE(EMemReplayAllocClass::C_UserPointer, EMemReplayUserPointerClass::C_CryMalloc);
		MEMREPLAY_SCOPE_FREE(ptr);
	}
};

#endif


//////////////////////////////////////////////////////////////////////////
// GSystemInitWrapper

class GSystemInitWrapper
{
public:
	GSystemInitWrapper()
	: m_pGFxMemInterface(0)
	{
		ScopedSwitchToGlobalHeap globalHeap;

		size_t staticPoolSize = CFlashPlayer::GetStaticPoolSize();
		if (staticPoolSize)
		{
			gEnv->pLog->Log("  Using static pool of %.1f MB", staticPoolSize / (1024.0f * 1024.0f));
			GSysAllocStaticCryMem* pStaticAlloc = new GSysAllocStaticCryMem(staticPoolSize);

			if (!pStaticAlloc || !pStaticAlloc->IsValid())
			{
				gEnv->pLog->LogWarning("  Failed to allocate memory for static pool! Switching to dynamic pool.");
				SAFE_DELETE(pStaticAlloc);
			}
			else
				m_pGFxMemInterface = pStaticAlloc;
		}

		if (!m_pGFxMemInterface)
		{
			gEnv->pLog->Log("  Using dynamic pool");
			m_pGFxMemInterface = new GSysAllocCryMem(CFlashPlayer::GetAddressSpaceSize());
		}

		assert(m_pGFxMemInterface && m_pGFxMemInterface->GetSysAllocImpl());
		GSystem::Init(m_pGFxMemInterface->GetSysAllocImpl());

#ifdef GHEAP_TRACE_ALL
		GMemory::GetGlobalHeap()->SetTracer(&m_heapTracer);
#endif
	}

	~GSystemInitWrapper()
	{
#ifdef GHEAP_TRACE_ALL
		GMemory::GetGlobalHeap()->SetTracer(NULL);
#endif

#if !defined(_RELEASE)
		if (IsTempMemoryArenaActive())
		{
			CryGFxLog::GetAccess().LogError("Still using temporary memory arena while shutting down GFx memory system! Enforce breaking into the debugger...");
			__debugbreak();
		}
#endif

		GSystem::Destroy();

		SAFE_DELETE(m_pGFxMemInterface);
	}

	CryGFxMemInterface* GetGFxMemInterface() { return m_pGFxMemInterface; }

	void GetMemoryUsage(ICrySizer* pSizer) const
	{
		pSizer->AddObject(this, sizeof(*this));
		pSizer->AddObject(m_pGFxMemInterface);
	}

	int CreateTempMemoryArena() const
	{
		assert(m_pGFxMemInterface);
		return m_pGFxMemInterface->GetTempMemoryArena().Create();
	}

	void DestoryTempMemoryArena() const
	{
		assert(m_pGFxMemInterface);
		m_pGFxMemInterface->GetTempMemoryArena().Destroy();
	}

	bool IsTempMemoryArenaActive() const
	{
		assert(m_pGFxMemInterface);
		return m_pGFxMemInterface->GetTempMemoryArena().IsActive();
	}

private:
	CryGFxMemInterface* m_pGFxMemInterface;

#ifdef GHEAP_TRACE_ALL
	CryMemReplayGHeapTracer m_heapTracer;
#endif
};


//////////////////////////////////////////////////////////////////////////
// CSharedFlashPlayerResources

CSharedFlashPlayerResources* CSharedFlashPlayerResources::ms_pSharedFlashPlayerResources = 0;

CSharedFlashPlayerResources& CSharedFlashPlayerResources::GetAccess()
{
	assert(ms_pSharedFlashPlayerResources);
	return *ms_pSharedFlashPlayerResources;
}


CSharedFlashPlayerResources::CSharedFlashPlayerResources()
: m_pGSystemInit(0)
, m_pLoader(0)
, m_pRenderer(0)
, m_pMeshCacheResetThread(0)
{
	ScopedSwitchToGlobalHeap globalHeap;

	gEnv->pLog->Log("Using Scaleform GFx "GFC_FX_VERSION_STRING);
	m_pGSystemInit = new GSystemInitWrapper();
	assert(m_pGSystemInit);
	m_pLoader = new GFxLoader2();
	m_pRenderer = new GRendererXRender();
	m_pMeshCacheResetThread = new MeshCacheResetThread();

	RegisterCryGImageInfoSystemEventListener();
}


CSharedFlashPlayerResources::~CSharedFlashPlayerResources()
{
	CFlashPlayer::DumpAndFixLeaks();
	SAFE_DELETE(m_pMeshCacheResetThread);
	assert(!m_pLoader || m_pLoader->GetRefCount() == 1);
	SAFE_RELEASE(m_pLoader);
	assert(!m_pRenderer || m_pRenderer->GetRefCount() == 1);
	SAFE_RELEASE(m_pRenderer);
	SAFE_DELETE(m_pGSystemInit);
}


void CSharedFlashPlayerResources::Init()
{
	assert(!ms_pSharedFlashPlayerResources);
	static char s_sharedFlashPlayerResourcesStorage[sizeof(CSharedFlashPlayerResources)] = {0};
	if (!ms_pSharedFlashPlayerResources)
		ms_pSharedFlashPlayerResources = new(s_sharedFlashPlayerResourcesStorage) CSharedFlashPlayerResources;
}


void CSharedFlashPlayerResources::Shutdown()
{
	assert(ms_pSharedFlashPlayerResources);
	if (ms_pSharedFlashPlayerResources)
	{
		ms_pSharedFlashPlayerResources->~CSharedFlashPlayerResources();
		ms_pSharedFlashPlayerResources = 0;
	}
}


GFxLoader2* CSharedFlashPlayerResources::GetLoader(bool getRawInterface)
{
	assert(m_pLoader);
	if (!getRawInterface)
		m_pLoader->AddRef();
	return m_pLoader;
}


GRendererXRender* CSharedFlashPlayerResources::GetRenderer(bool getRawInterface)
{
	assert(m_pRenderer);
	if (!getRawInterface)
		m_pRenderer->AddRef();
	return m_pRenderer;
}


CryGFxMemInterface::Stats CSharedFlashPlayerResources::GetSysAllocStats() const
{
	CryGFxMemInterface::Stats stats = {0};
	if (m_pGSystemInit)
	{
		CryGFxMemInterface* p = m_pGSystemInit->GetGFxMemInterface();
		if (p)
			stats = p->GetStats();
	}
	return stats;
}


void CSharedFlashPlayerResources::GetMemoryUsage(ICrySizer* pSizer) const
{
	assert(pSizer);
	pSizer->AddObject(m_pGSystemInit);
	pSizer->AddObject(m_pLoader);
	pSizer->AddObject(m_pRenderer);
}


int CSharedFlashPlayerResources::CreateTempMemoryArena() const
{
	assert(m_pGSystemInit);
	return m_pGSystemInit->CreateTempMemoryArena();
}


void CSharedFlashPlayerResources::DestoryTempMemoryArena() const
{
	assert(m_pGSystemInit);
	return m_pGSystemInit->DestoryTempMemoryArena();
}


bool CSharedFlashPlayerResources::IsTempMemoryArenaActive() const
{
	assert(m_pGSystemInit);
	return m_pGSystemInit->IsTempMemoryArenaActive();
}


void CSharedFlashPlayerResources::ResetMeshCache() const
{
	if (m_pMeshCacheResetThread)
		m_pMeshCacheResetThread->IssueReset();
}


//////////////////////////////////////////////////////////////////////////
// GFxLoader2

static inline GPtr<GFxJpegSupportBase> CreateJpegSupport()
{
#if defined(USE_GFX_JPG)
	return *new GFxJpegSupport;
#else
	return 0;
#endif
}

GFxLoader2::GFxLoader2()
: GFxLoader(&CryGFxFileOpener::GetAccess(), GFX_LOADER_NEW_ZLIBSUPPORT, CreateJpegSupport())
, m_refCount(1)
, m_parserVerbosity()
{
	// set callbacks
	SetLog(&CryGFxLog::GetAccess());
	//SetFileOpener(&CryGFxFileOpener::GetAccess());
	SetURLBuilder(&CryGFxURLBuilder::GetAccess());
	SetImageCreator(&CryGFxImageCreator::GetAccess());
	SetImageLoader(&CryGFxImageLoader::GetAccess());
	SetTranslator(&CryGFxTranslator::GetAccess());

	// enable dynamic font cache
	SetupDynamicFontCache();

	// set parser verbosity
	UpdateParserVerbosity();
	SetParseControl(&m_parserVerbosity);

	// set up png support
#if defined(USE_GFX_PNG)
	GPtr<GFxPNGSupport> pPNGSupport = *new GFxPNGSupport();
	SetPNGSupport(pPNGSupport);
#endif

	// set up video
#if defined(USE_GFX_VIDEO)
	GFxVideoWrapper::SetVideo(this);
#endif
}


GFxLoader2::~GFxLoader2()
{
	SetParseControl(0);
}


void GFxLoader2::AddRef()
{
	CryInterlockedIncrement(&m_refCount);
}


void GFxLoader2::Release()
{
	long refCount = CryInterlockedDecrement(&m_refCount);
	if (refCount <= 0)
		delete this;
}


void GFxLoader2::UpdateParserVerbosity()
{
	m_parserVerbosity.SetParseFlags((CFlashPlayer::GetLogOptions() & CFlashPlayer::LO_LOADING) ? 
		GFxParseControl::VerboseParseAll : GFxParseControl::VerboseParseNone);
}


void GFxLoader2::SetupDynamicFontCache()
{
	SetFontPackParams(0);

	GFxFontCacheManager* pFontCacheMan(GetFontCacheManager());
	pFontCacheMan->EnableDynamicCache(true);
	pFontCacheMan->SetMaxRasterScale(1.25f);

	struct HalfValueOnConsoles
	{
		uint32 val;
		HalfValueOnConsoles(uint32 v) : val(v) {}
		operator uint32() const
		{



			return val;

		}
	};

	GFxFontCacheManager::TextureConfig cfg;
	cfg.TextureWidth = 1024; //HalfValueOnConsoles(1024);
	cfg.TextureHeight = 1024; //HalfValueOnConsoles(1024);
	cfg.MaxNumTextures = 1;
	cfg.MaxSlotHeight = 48;
	cfg.SlotPadding = 2;
	cfg.TexUpdWidth = HalfValueOnConsoles(256);
	cfg.TexUpdHeight = HalfValueOnConsoles(512);
	pFontCacheMan->SetTextureConfig(cfg);
}


//////////////////////////////////////////////////////////////////////////
// MeshCacheResetThread

const char* MeshCacheResetThread::ms_pThreadName = "GFxMeshCacheReset";

MeshCacheResetThread::MeshCacheResetThread()
: m_cancelRequestSent(false)
, m_awakeThread()
{
	Start(THREAD_PRIORITY_NORMAL, ms_pThreadName);
}


MeshCacheResetThread::~MeshCacheResetThread()
{
	Cancel();
	WaitForThread();
	Stop();
}


void MeshCacheResetThread::Cancel()
{
	m_cancelRequestSent = true;
	m_awakeThread.Set();
}


void MeshCacheResetThread::IssueReset()
{
	m_awakeThread.Set();
}


#endif // #ifndef EXCLUDE_SCALEFORM_SDK